﻿////////////////////////////////////////////////////////////////////////////////////////////////////
// file:	Test\TestReadUncommitted.cs
//
// summary:	隔离级别读未提交，会出现“脏读”现象
//                     A事务执行过程中，B事务读取了A事务的修改，但是A事务并没有提交，A事务后来可能成功也可能失败。
////////////////////////////////////////////////////////////////////////////////////////////////////

using System;
using System.Linq;
using System.Threading;
using System.Transactions;
using Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using NUnit.Framework;

namespace TestTransaction.Test
{
    class TestReadUncommitted :TestBase
    {
        private AutoResetEvent _autoResetEvent;

        [Test]
        public void ReadUncommitted()
        {
            using (var context = _autofacServiceProvider.GetService<OpenAuthDBContext>())
            {
                var user = context.Users.SingleOrDefault(u => u.Account == "admin");
                Console.WriteLine($"初始用户状态:【{user.Status}】");
            }

            _autoResetEvent = new AutoResetEvent(false);
            ThreadPool.QueueUserWorkItem(data =>{
                Write();  //启动线程写
            });
            ThreadPool.QueueUserWorkItem(data =>{
                Read();  //启动线程读
            });

            Thread.Sleep(5000);

            using (var context = _autofacServiceProvider.GetService<OpenAuthDBContext>())
            {
                var user = context.Users.SingleOrDefault(u => u.Account == "admin");
                Console.WriteLine($"最终用户状态:【{user.Status}】");
            }
        }

        private void Read()
        {
            _autoResetEvent.WaitOne();

            var options = new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted };
            using (var scope = new TransactionScope(TransactionScopeOption.Required, options))
            {
                using (var context = _autofacServiceProvider.GetService<OpenAuthDBContext>())
                {
                    var user = context.Users.SingleOrDefault(u => u.Account == "admin");
                    Console.WriteLine($"事务B：脏读到的用户状态:【{user.Status}】--{DateTime.Now.ToString("HH:mm:ss fff")}");
                    //如果这时执行下面的判断
                    if (user.Status == 1)
                    {
                        Console.WriteLine("事务B：非正常数据，会产生意想不到的BUG😎");
                    }
                }
            }
        }
        private void Write()
        {
            using (var scope = new TransactionScope(TransactionScopeOption.Required, 
                new TransactionOptions {IsolationLevel = IsolationLevel.ReadCommitted}))
            {
                Console.WriteLine($"事务A：修改--{DateTime.Now.ToString("HH:mm:ss fff")}");
                using (var context = _autofacServiceProvider.GetService<OpenAuthDBContext>())
                {
                    var user = context.Users.SingleOrDefault(u => u.Account == "admin");
                    user.Status = 1-user.Status;  //模拟修改
                    context.SaveChanges();
                }

                _autoResetEvent.Set();  //模拟多线程切换，这时切换到Read线程，复现脏读

                Thread.Sleep(2000);  //模拟长事务
                Console.WriteLine($"事务A：改完，但没提交--{DateTime.Now.ToString("HH:mm:ss fff")}");
            }
        }
    }
}
